/***************************************************************************
                          gm4lin.c  -  main program
                             -------------------
    begin                : Thu Dec 12 14:59:53 GST 2002
    copyright            : (C) 2003 by Mathias Bavay
    email                : mbavay@crtholdings.com
 ***************************************************************************/

/***************************************************************************
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 ***************************************************************************/
#include "acquisition.h"

int activity_recording(struct probe_descriptor probe[],struct configuration_struct *settings) {
/* Running probes in activity recording mode */
/* returns EXIT_SUCCESS or EXIT_FAILURE */
	fd_set file_descriptor_set;				/* file descriptor set of probes */
	#ifdef PSELECT
	sigset_t blocking_sigmask,original_sigmask;		/* signals mask in order to avoid a race condition in the main loop, */
								/* (SIGALRM generated before the program beeing able to handle it) */
	#endif
	int probe_index;					/* index of the probe */
	int events;						/* number of ports which have seen an event */

	#ifdef PSELECT
		/* creating the signal masks */
		/* in the main loop, SIGALRM will be masked -> if it happens, it will be pending */
		/* the old mask (ie: with SIGALRM not blocked) is given to pselect -> SIGALRM can be received by pselect */
		#ifdef DEBUG
			printf("\tusing pselect() instead of select() for events detection\n");
		#endif
		if(sigemptyset(&blocking_sigmask)!=EXIT_SUCCESS) {
			error_log(_("activity_recording: error for sigemptyset\n"));
			return EXIT_FAILURE;
		}
		if(sigaddset(&blocking_sigmask,SIGALRM)!=EXIT_SUCCESS) {
			error_log(_("activity_recording: error for sigaddset\n"));
			return EXIT_FAILURE;
		}
		if(sigprocmask(SIG_BLOCK,&blocking_sigmask,&original_sigmask)!=EXIT_SUCCESS) {
			error_log(_("activity_recording: error for sigprocmask\n"));
			return EXIT_FAILURE;
		}
	#else
		#ifdef DEBUG
			printf("\tusing select() for events detection\n");
		#endif
	#endif
	printf(_("Running probes in activity recording mode...(refresh delay=%d seconds)\n"),settings->activity_data_write_sampling);
	do {
		/* re-initializing the set of file descriptors */
		FD_ZERO(&file_descriptor_set);
		/* building the set of file descriptors */
		for(probe_index=0;probe_index<settings->num_probes;probe_index++) {
			FD_SET(probe[probe_index].file_descriptor,&file_descriptor_set);
		}
		#ifdef DEBUG
			printf("\tSelect waiting for input (fd_max+1=%d)...\n",settings->file_descriptor_max+1);
		#endif
		/* running probes */
		#ifdef PSELECT
		if(((events=pselect(settings->file_descriptor_max+1,&file_descriptor_set,NULL,NULL,NULL,&original_sigmask)) == -1) && !flag_stop && !flag_alrm) {
		#else
		if(((events=select(settings->file_descriptor_max+1,&file_descriptor_set,NULL,NULL,NULL)) == -1) && !flag_stop && !flag_alrm) {
		#endif
			error_log(_("activity_recording: pselect/select call failed"));
			return EXIT_FAILURE;
		}
		if(events > 0) { /* when flag_alrm is ON, events <0 */
			#ifdef DEBUG
				printf("\tEvent detected on %d port(s)\n",events);
			#endif
			/* at least 1 port has seen something */
			for(probe_index=0;probe_index<settings->num_probes;probe_index++) {
				if(FD_ISSET(probe[probe_index].file_descriptor,&file_descriptor_set)) {
					/* one more event for that probe */
					probe[probe_index].value++;
					/* we need to read the port in order to clear it */
					clear_port(probe[probe_index].file_descriptor);
				}
			}	
		}
		if(flag_alrm && !flag_stop) {
			flag_alrm=0;
			data_log(probe,settings);
		}
	} while (!flag_stop);
	#ifdef PSELECT
		/* in order to exit in a clean way, we restore the signal mask as it was before entering this function */
		if(sigprocmask(SIG_UNBLOCK,&blocking_sigmask,NULL)!=EXIT_SUCCESS) {
			error_log(_("activity_recording: error for sigprocmask when restoring original signal mask\n"));
			return EXIT_FAILURE;
		}
	#endif
	
	return EXIT_SUCCESS;
}

int pulse_recording(struct probe_descriptor probe[],struct configuration_struct *settings) {
/* Running probes in pulse recording mode*/
/* returns EXIT_SUCCESS or EXIT_FAILURE */
	float exponential_factor;				/* multiplication factor for pulse mode */
	int probe_index;					/* index of the probe */
	#ifdef PSELECT
	sigset_t blocking_sigmask,original_sigmask;		/* signals mask in order to avoid a race condition in the main loop, */
								/* (SIGALRM generated before the program beeing able to handle it) */
	#endif

	#ifdef PSELECT
		/* creating the signal masks */
		/* in the main loop, SIGALRM will be masked -> if it happens, it will be pending */
		/* the old mask (ie: with SIGALRM not blocked) is given to pselect -> SIGALRM can be received by pselect */
		#ifdef DEBUG
			printf("\tusing pselect() instead of select() for signals detection\n");
		#endif
		if(sigemptyset(&blocking_sigmask)!=EXIT_SUCCESS) {
			error_log(_("activity_recording: error for sigemptyset\n"));
			return EXIT_FAILURE;
		}
		if(sigaddset(&blocking_sigmask,SIGALRM)!=EXIT_SUCCESS) {
			error_log(_("activity_recording: error for sigaddset\n"));
			return EXIT_FAILURE;
		}
		if(sigprocmask(SIG_BLOCK,&blocking_sigmask,&original_sigmask)!=EXIT_SUCCESS) {
			error_log(_("activity_recording: error for sigprocmask\n"));
			return EXIT_FAILURE;
		}
	#else
		#ifdef DEBUG
			printf("\tusing select() for signals detection\n");
		#endif
	#endif
	printf(_("Running probes in pulse recording mode...(refresh delay=%d seconds, decay time=%3.3f)\n"),settings->pulse_data_write_sampling,INTEGRATION_RC);
	/* initializing the exponential factor which is going to multiply the signals */
	exponential_factor=(float)exp(-(double)settings->pulse_particule_sub_sampling/(double)INTEGRATION_RC*1.0e-3);
	/* reading data... */
	do {
		/* waiting for a signal to be generated... */
		#ifdef PSELECT
			if((pselect(0,NULL,NULL,NULL,NULL,&original_sigmask)==-1) && !flag_stop && !flag_alrm) {
		#else
			if((select(0,NULL,NULL,NULL,NULL)==-1) && !flag_stop && !flag_alrm) {
		#endif	
			error_log(_("pulse_recording: pselect/select call failed"));
			return EXIT_FAILURE;
		}
		if(flag_alrm && !flag_stop) {
			flag_alrm=0;
			/* it is time to read data from the detectors */
			for(probe_index=0;probe_index<settings->num_probes;probe_index++) {
				probe[probe_index].value *= exponential_factor;
				if((probe_port(probe[probe_index].file_descriptor))>0) probe[probe_index].value += 1;
			}
			settings->pulse_mode_particules_sampling_count++;
			if(settings->pulse_mode_particules_sampling_count>=settings->pulse_mode_particules_sampling_write) {
				settings->pulse_mode_particules_sampling_count=0;
				data_log(probe,settings);
			}
		}
	} while (!flag_stop);
	#ifdef PSELECT
		/* in order to exit in a clean way, we restore the signal mask as it was before entering this function */
		if(sigprocmask(SIG_UNBLOCK,&blocking_sigmask,NULL)!=EXIT_SUCCESS) {
			error_log(_("activity_recording: error for sigprocmask when restoring original signal mask\n"));
			return EXIT_FAILURE;
		}
	#endif
	
	return EXIT_SUCCESS;
}

int stop_probes(struct probe_descriptor probe[],struct configuration_struct *settings) {
/* Closing the probes */
/* returns EXIT_SUCCESS or EXIT_FAILURE if everything was not ok */
/* anyway, we try to close as much files, file_descriptors, ... as possible */
	int probe_index;			/* index of the probe */
	int return_value;			/* in order to know the global exit status */

	return_value=EXIT_SUCCESS;
	for(probe_index=0;probe_index<settings->num_probes;probe_index++) {
		if ((stop_probe(&probe[probe_index],settings)) == EXIT_FAILURE) {
			error_log(_("stop_probes: probe can not be stopped"));
			return_value=EXIT_FAILURE;
		}
		/* closing the log file */
		if (settings->file_log==EXIT_SUCCESS) {
			if (probe[probe_index].log_file!=NULL) {
			/* If file logging has been disabled for some probes, then log_file is NULL */
				if ((fclose(probe[probe_index].log_file)) != EXIT_SUCCESS){
					error_log(_("stop_probes: Log file can not be closed"));
					return_value=EXIT_FAILURE;
				}
				#ifdef DEBUG
					printf("\tlog file[%d] closed\n",probe[probe_index].index);
				#endif
			}
		}
	}
	return return_value;
}
